package org.example.util;

import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 时间工具类
 *
 * @author: zk
 * @date: 2023/6/25 16:11
 */

public class DateUtils {
    public static final String CN_TIME_ZONE_ID = "Asia/Shanghai";
    private static final int NUM_2 = 2;

    /**
     * 线程安全的日期格式对象
     */
    private static final ThreadLocal<DateFormat> DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

    private static final ThreadLocal<DateFormat> TIME_FMT_STR = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMddHHmm"));

    private static final ThreadLocal<DateFormat> TIME_FMT_COMPLETE_STR = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMddHHmmss"));

    /**
     * 线程安全的日期格式对象
     */
    private static final ThreadLocal<DateFormat> YMD = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

    private static final ThreadLocal<DateFormat> YM = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM"));

    private static final ThreadLocal<DateFormat> HH = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH"));

    /**
     * 线程安全的日期格式对象
     */
    private static final ThreadLocal<DateFormat> YMD_STR = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd"));

    private static final ThreadLocal<DateFormat> HOUR_X = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:00"));
    private static final ThreadLocal<DateFormat> MONTH_DAY_X = ThreadLocal.withInitial(() -> new SimpleDateFormat("MM-dd"));
    private static final ThreadLocal<DateFormat> YEAR_MONTH_X = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM"));

    /**
     * 格式化完整日期
     *
     * @return yyyy-MM-dd HH:mm:ss格式的字符串
     */
    public static String formatDate(Date date) {
        return DATE_FORMAT.get().format(date);
    }

    /**
     * 格式化完整日期
     *
     * @return yyyyMMddHHmmss格式的字符串
     */
    public static String formatCompleteTime(Date date) {
        return TIME_FMT_COMPLETE_STR.get().format(date);
    }

    /**
     * 格式化年月日
     *
     * @return yyyy-MM-dd格式的字符串
     */
    public static String formatYMD(Date date) {
        return YMD.get().format(date);
    }

    /**
     * 格式化年月
     *
     * @param date date
     * @return String
     */
    public static String formatYM(Date date) {
        return YM.get().format(date);
    }

    /**
     * 格式化小时
     *
     * @param date date
     * @return String
     */
    public static String formatHH(Date date) {
        return HH.get().format(date);
    }

    /**
     * 格式化年月日
     *
     * @return yyyyMMdd格式的字符串
     */
    public static String formatYMDStr(Date date) {
        return YMD_STR.get().format(date);
    }

    public static String formatHourX(Date date) {
        return HOUR_X.get().format(date);
    }

    public static String formatMonthDayX(Date date) {
        return MONTH_DAY_X.get().format(date);
    }

    public static String formatYearMonthX(Date date) {
        return YEAR_MONTH_X.get().format(date);
    }

    /**
     * 解析时间
     *
     * @param timeStr str
     * @return Date
     * @throws ParseException e
     */
    public static Date parseDate(String timeStr) throws ParseException {
        return DATE_FORMAT.get().parse(timeStr);
    }

    /**
     * 获取指定日期0点的字符串
     *
     * @return 返回示例:2017-12-23 00:00:00
     */
    public static String getZeroPointStr(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return formatDate(calendar.getTime());
    }

    /**
     * 获取指定日期末点的字符串
     *
     * @return 返回示例:2017-12-23 23:59:59
     */
    public static String getLastPointStr(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return formatDate(calendar.getTime());
    }

    /**
     * 获取指定日期的0点的毫秒数
     */
    public static long getZeroPointMillisecond(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime().getTime();
    }

    /**
     * 获取指定日期的末点的毫秒数
     */
    public static long getLastPointMillisecond(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime().getTime();
    }

    /**
     * Long整形转化Timestamp
     */
    public static Timestamp long2Timestamp(long time) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(time);
        return new Timestamp(date.getTimeInMillis());
    }

    public static long timestamp2Long(Timestamp timestamp) {
        return timestamp == null ? 0 : timestamp.getTime();
    }

    public static Timestamp date2Timestamp(Date date) {
        return date == null ? null : new Timestamp(date.getTime());
    }

    public static Date timestamp2Date(Timestamp timestamp) {
        return new Date(timestamp.getTime());
    }

    public static String timestamp2String(Timestamp timestamp) {
        return formatDate(new Date(timestamp.getTime()));
    }

    public static String date2String(Date date) {
        return formatDate(date);
    }

    public static String longTime2String(long time, TimeUnit unit) {
        if (TimeUnit.SECONDS.equals(unit) || TimeUnit.MILLISECONDS.equals(unit)) {
            Calendar date = Calendar.getInstance();
            if (TimeUnit.SECONDS.equals(unit)) {
                time = time * 1000;
            }
            date.setTimeInMillis(time);
            return date2String(date.getTime());
        }
        return null;
    }

    public static String timestamp2YmdString(Timestamp timestamp) {
        return formatYMD(new Date(timestamp.getTime()));
    }

    public static String timestamp2DateString(Timestamp timestamp) {
        return formatDate(new Date(timestamp.getTime()));
    }

    public static String date2YmdString(Date date) {
        return formatYMD(date);
    }

    /**
     * 根据当前时间加上时长(日),产生新的时间
     *
     * @param dateAmount 天数
     * @return 时间
     */
    public static Long getLongTimeAfterDate(int dateAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.DATE, dateAmount);
        return date.getTimeInMillis();
    }

    /**
     * 根据指定时间加上时长(日),产生新的时间
     *
     * @param timestamp  指定时间
     * @param dateAmount 天数
     * @return 时间
     */
    public static Long getLongTimeAfterDate(Timestamp timestamp, int dateAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(timestamp.getTime());
        date.add(Calendar.DATE, dateAmount);
        return date.getTimeInMillis();
    }

    /**
     * 根据当前时间加上时长(日),产生新的时间
     *
     * @param dateAmount 天数
     * @return 时间
     */
    public static Timestamp getTimeAfterDays(int dateAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.DATE, dateAmount);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(月),产生新的时间
     *
     * @param dayAmount 天数
     * @return 时间
     */
    public static String getStrTimeAfterDay(int dayAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.DATE, dayAmount);
        return formatDate(date.getTime());
    }

    /**
     * 根据指定时间加上时长(日),产生新的时间
     *
     * @param timestamp  指定时间
     * @param dayAmount 天数
     * @return 时间
     */
    public static Timestamp getTimeAfterDay(Timestamp timestamp, int dayAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(timestamp.getTime());
        date.add(Calendar.DATE, dayAmount);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(月),产生新的时间
     *
     * @param monthAmount 月数
     * @return 时间
     */
    public static Timestamp getTimeAfterMonth(int monthAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.MONTH, monthAmount);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据指定时间加上时长(月),产生新的时间
     *
     * @param timestamp   指定时间
     * @param monthAmount 月数
     * @return 时间
     */
    public static Timestamp getTimeAfterMonth(Timestamp timestamp, int monthAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(timestamp.getTime());
        date.add(Calendar.MONTH, monthAmount);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(月),产生新的时间
     *
     * @param monthAmount 月数
     * @return 时间
     */
    public static String getStrTimeAfterMonth(int monthAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.MONTH, monthAmount);
        return formatDate(date.getTime());
    }

    /**
     * 根据当前时间加上时长(年),产生新的时间
     *
     * @param yearAmount 年数
     * @return 时间
     */
    public static int getYearAfterYear(int yearAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.YEAR, yearAmount);
        return date.get(Calendar.YEAR);
    }

    /**
     * 根据当前时间加上时长(年),产生新的时间
     *
     * @param yearAmount 年数
     * @return 时间
     */
    public static Timestamp getTimeAfterYear(int yearAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.YEAR, yearAmount);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(年),产生新的时间
     *
     * @param yearAmount 年数
     * @return 时间
     */
    public static String getStrTimeAfterYear(int yearAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.YEAR, yearAmount);
        return formatDate(date.getTime());
    }

    /**
     * 根据指定时间加上时长(年),产生新的时间
     *
     * @param timestamp  指定时间
     * @param yearAmount 年数
     * @return 时间
     */
    public static Timestamp getTimeAfterYear(Timestamp timestamp, int yearAmount) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(timestamp.getTime());
        date.add(Calendar.YEAR, yearAmount);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(日),产生新的时间
     *
     * @param second 秒数
     * @return 时间
     */
    public static Timestamp getTimeAfterSecond(Timestamp timestamp, int second) {
        Calendar date = Calendar.getInstance();
        date.setTimeZone(TimeZone.getTimeZone(CN_TIME_ZONE_ID));
        date.setTimeInMillis(timestamp.getTime());
        date.add(Calendar.SECOND, second);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据指定日期格式将字符串表示的日期转换成Date对象
     *
     * @param date   字符串表示的日期
     * @param format 日期格式
     * @return 返回转换后的Date对象，如果字符串解析错误则返回null
     */
    public static Date getDateFromString(String date, String format, String timeZone) {
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
            if (!ObjectUtils.isEmpty(timeZone)) {
                dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
            }
            return dateFormat.parse(date);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 根据指定时间加上时长(小时),产生新的时间
     *
     * @param timestamp 指定时间
     * @param hour      小时数
     * @return 时间
     */
    public static Timestamp getTimeAfterHour(Timestamp timestamp, int hour) {
        Calendar date = Calendar.getInstance();
        date.setTimeZone(TimeZone.getTimeZone(CN_TIME_ZONE_ID));
        date.setTimeInMillis(timestamp.getTime());
        date.add(Calendar.HOUR_OF_DAY, hour);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(小时),产生新的时间
     *
     * @param hour 小时数
     * @return 时间
     */
    public static Timestamp getTimeAfterHour(int hour) {
        Calendar date = Calendar.getInstance();
        date.setTimeZone(TimeZone.getTimeZone(CN_TIME_ZONE_ID));
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.HOUR_OF_DAY, hour);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据指定时间加上时长(分钟),产生新的时间
     *
     * @param timestamp 指定时间
     * @param minute    分钟数
     * @return 时间
     */
    public static Timestamp getTimeAfterMinute(Timestamp timestamp, int minute) {
        Calendar date = Calendar.getInstance();
        date.setTimeZone(TimeZone.getTimeZone(CN_TIME_ZONE_ID));
        date.setTimeInMillis(timestamp.getTime());
        date.add(Calendar.MINUTE, minute);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(分钟),产生新的时间
     *
     * @param minute 分钟数
     * @return 时间
     */
    public static Timestamp getTimeAfterMinute(int minute) {
        Calendar date = Calendar.getInstance();
        date.setTimeZone(TimeZone.getTimeZone(CN_TIME_ZONE_ID));
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.MINUTE, minute);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据指定时间加上时长(日),产生新的时间
     *
     * @param timestamp 指定时间
     * @param minute    分钟数
     * @return 时间
     */
    public static Long getLongTimeAfterMinute(long timestamp, int minute) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(timestamp);
        date.add(Calendar.MINUTE, minute);
        return date.getTimeInMillis();
    }

    /**
     * 根据当前时间加上时长(日),产生新的时间
     *
     * @param second 秒数
     * @return 时间
     */
    public static Timestamp getTimeAfterSecond(int second) {
        Calendar date = Calendar.getInstance();
        date.setTimeZone(TimeZone.getTimeZone(CN_TIME_ZONE_ID));
        date.setTimeInMillis(System.currentTimeMillis());
        date.add(Calendar.SECOND, second);
        return new Timestamp(date.getTimeInMillis());
    }

    /**
     * 根据指定时间加上时长(日),产生新的时间
     *
     * @param timestamp 指定时间
     * @param second    秒数
     * @return 时间
     */
    public static Long getLongTimeAfterSecond(long timestamp, int second) {
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(timestamp);
        date.add(Calendar.SECOND, second);
        return date.getTimeInMillis();
    }


    public static Timestamp getCurrentTime() {
        return new Timestamp(System.currentTimeMillis());
    }

    public static int getHour() {
        Calendar date = Calendar.getInstance();
        return date.get(Calendar.HOUR_OF_DAY);
    }

    public static Date getCurrentDate() {
        return new Date(System.currentTimeMillis());
    }

    public static String getCurrentStringDate() {
        return formatDate(new Date(System.currentTimeMillis()));
    }

    public static String getCurrentStringTime() {
        return TIME_FMT_STR.get().format(new Date(System.currentTimeMillis()));
    }

    public static String time2String(Date date) {
        return TIME_FMT_STR.get().format(date);
    }

    public static String getCurrentTimeCompleteStringDate() {
        return formatCompleteTime(new Date(System.currentTimeMillis()));
    }

    /**
     * 获取当前时间的特定格式
     *
     * @return now
     */
    public static String getNow() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        return sdf.format(new Date());
    }

    /**
     * 获取昨天日期0点的时间戳
     */
    public static Timestamp getZeroPointTimeBeforeNow() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.DATE, -1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取上周一0点的时间戳
     */
    public static Timestamp getZeroPointTimeBeforeMonday() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.DATE, -7);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取上月1号0点的时间戳
     */
    public static Timestamp getZeroPointTimeBeforeMonthStart() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(日),起始时间
     *
     * @param dateAmount 天数
     * @return 时间
     */
    public static Timestamp getZeroPointTimeAfterDate(int dateAmount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.DATE, dateAmount);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(日),终点时间
     *
     * @param dateAmount 天数
     * @return 时间
     */
    public static Timestamp getLastPointTimeAfterDate(int dateAmount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.DATE, dateAmount);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(月),开始时间
     *
     * @param monthAmount 月
     * @return time
     */
    public static Timestamp getZeroPointTimeAfterMonth(int monthAmount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.MONTH, monthAmount);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 根据当前时间加上时长(月),终点时间
     *
     * @param monthAmount 月
     * @return time
     */
    public static Timestamp getLastPointTimeAfterMonth(int monthAmount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.MONTH, monthAmount);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DATE));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取定时日期的执行时间
     *
     * @param year   年
     * @param month  月
     * @param day    日
     * @param hour   时
     * @param minute 分
     * @param second 秒
     * @return time
     */
    public static Timestamp getNextTimeForDay(Integer year, Integer month, Integer day, Integer hour, Integer minute, Integer second) throws ParseException {
        String time = year + "-" + (month < 10 ? ("0" + month) : month) + "-" + (day < 10 ? ("0" + day) : day);
        time += " " + (hour < 10 ? ("0" + hour) : hour) + ":"
                + (minute < 10 ? ("0" + minute) : minute) + ":"
                + (second < 10 ? ("0" + second) : second);
        Date date = parseDate(time);
        return new Timestamp(date.getTime());
    }


    /**
     * 按月度取下次时间
     *
     * @param day    下月日期
     * @param hour   小时
     * @param minute 分钟
     * @param second 秒
     * @return time
     */
    public static Timestamp getNextMonthTime(Integer day, Integer hour, Integer minute, Integer second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        int currDay = calendar.get(Calendar.DAY_OF_MONTH);
        // 当前月的最后一天
        int maxDay = calendar.getActualMaximum(Calendar.DATE);
        int newDay = day;
        // 超过当前月最后一天，取最后一天
        if (newDay > maxDay) {
            newDay = maxDay;
        }
        // 不超过当前日，取下月；超过当前日，取本月
        if (newDay <= currDay) {
            calendar.add(Calendar.MONTH, 1);
        }
        maxDay = calendar.getActualMaximum(Calendar.DATE);
        if (day > maxDay) {
            day = maxDay;
        }
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 按季度取下次时间
     *
     * @param month  下季度第几个月
     * @param day    日期
     * @param hour   小时
     * @param minute 分钟
     * @param second 秒
     * @return time
     */
    public static Timestamp getNextQuarterTime(Integer month, Integer day, Integer hour, Integer minute, Integer second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        int currMonth = calendar.get(Calendar.MONTH);
        if (currMonth == Calendar.JANUARY
                || currMonth == Calendar.APRIL
                || currMonth == Calendar.JULY
                || currMonth == Calendar.OCTOBER) {
            // 当前为季度第一个月
            if (month == 1) {
                int currDay = calendar.get(Calendar.DAY_OF_MONTH);
                // 当前月的最后一天
                int maxDay = calendar.getActualMaximum(Calendar.DATE);
                int newDay = day;
                // 超过当前月最后一天，取最后一天
                if (newDay > maxDay) {
                    newDay = maxDay;
                }
                // 不超过当前日，取下季度
                if (newDay <= currDay) {
                    calendar.add(Calendar.MONTH, 2 + month);
                }
            } else {
                // 取本季度对应月份
                calendar.add(Calendar.MONTH, month - 1);
            }
        } else if (currMonth == Calendar.FEBRUARY
                || currMonth == Calendar.MAY
                || currMonth == Calendar.AUGUST
                || currMonth == Calendar.NOVEMBER) {
            // 当前为季度第二个月
            if (month == 3) {
                // 取本季度对应月份
                calendar.add(Calendar.MONTH, month - 2);
            } else if (month == 2) {
                int currDay = calendar.get(Calendar.DAY_OF_MONTH);
                // 当前月的最后一天
                int maxDay = calendar.getActualMaximum(Calendar.DATE);
                int newDay = day;
                // 超过当前月最后一天，取最后一天
                if (newDay > maxDay) {
                    newDay = maxDay;
                }
                // 不超过当前日，取下季度
                if (newDay <= currDay) {
                    calendar.add(Calendar.MONTH, 1 + month);
                }
            } else {
                // 取下季度
                calendar.add(Calendar.MONTH, 1 + month);
            }
        } else {
            // 当前为季度第三个月
            if (month == 3) {
                int currDay = calendar.get(Calendar.DAY_OF_MONTH);
                // 当前月的最后一天
                int maxDay = calendar.getActualMaximum(Calendar.DATE);
                int newDay = day;
                // 超过当前月最后一天，取最后一天
                if (newDay > maxDay) {
                    newDay = maxDay;
                }
                // 不超过当前日，取下季度
                if (newDay <= currDay) {
                    calendar.add(Calendar.MONTH, month);
                }
            } else {
                calendar.add(Calendar.MONTH, month);
            }
        }
        int maxDay = calendar.getActualMaximum(Calendar.DATE);
        if (day > maxDay) {
            day = maxDay;
        }
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 按年度取下次时间
     *
     * @param month  下年度第几个月
     * @param day    日期
     * @param hour   小时
     * @param minute 分钟
     * @param second 秒
     * @return time
     */
    public static Timestamp getNextYearTime(Integer month, Integer day, Integer hour, Integer minute, Integer second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        int currMonth = calendar.get(Calendar.MONTH) + 1;
        if (month < currMonth) {
            // 取下一年
            calendar.add(Calendar.YEAR, 1);
            calendar.set(Calendar.MONTH, month - 1);
        } else if (month == currMonth) {
            int currDay = calendar.get(Calendar.DAY_OF_MONTH);
            // 当前月的最后一天
            int maxDay = calendar.getActualMaximum(Calendar.DATE);
            int newDay = day;
            // 超过当前月最后一天，取最后一天
            if (newDay > maxDay) {
                newDay = maxDay;
            }
            // 不超过当前日，取下一年
            if (newDay <= currDay) {
                calendar.add(Calendar.YEAR, 1);
            }
        } else {
            calendar.set(Calendar.MONTH, month - 1);
        }
        int maxDay = calendar.getActualMaximum(Calendar.DATE);
        if (day > maxDay) {
            day = maxDay;
        }
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取上一周的起始时间(周一)
     *
     * @return Timestamp
     */
    public static Timestamp getPreviousWeekZeroTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        if (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
            calendar.add(Calendar.DATE, -7);
        } else {
            calendar.add(Calendar.DATE, -14);
        }
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取上一周的结束时间(周日)
     *
     * @return Timestamp
     */
    public static Timestamp getPreviousWeekLastTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
            calendar.add(Calendar.DATE, -7);
        }
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取上月的起始时间
     *
     * @return Timestamp
     */
    public static Timestamp getPreviousMonthZeroTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取上月的结束时间
     *
     * @return Timestamp
     */
    public static Timestamp getPreviousMonthLastTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DATE));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取上季度的起始时间
     *
     * @return Timestamp
     */
    public static Timestamp getPreviousQuarterZeroTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        int month = calendar.get(Calendar.MONTH);
        if (month == Calendar.JANUARY
                || month == Calendar.APRIL
                || month == Calendar.JULY
                || month == Calendar.OCTOBER) {
            calendar.add(Calendar.MONTH, -3);
        } else if (month == Calendar.FEBRUARY
                || month == Calendar.MAY
                || month == Calendar.AUGUST
                || month == Calendar.NOVEMBER) {
            calendar.add(Calendar.MONTH, -4);
        } else {
            calendar.add(Calendar.MONTH, -5);
        }
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取上季度的结束时间
     *
     * @return Timestamp
     */
    public static Timestamp getPreviousQuarterLastTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        int month = calendar.get(Calendar.MONTH);
        if (month == Calendar.JANUARY
                || month == Calendar.APRIL
                || month == Calendar.JULY
                || month == Calendar.OCTOBER) {
            calendar.add(Calendar.MONTH, -1);
        } else if (month == Calendar.FEBRUARY
                || month == Calendar.MAY
                || month == Calendar.AUGUST
                || month == Calendar.NOVEMBER) {
            calendar.add(Calendar.MONTH, -2);
        } else {
            calendar.add(Calendar.MONTH, -3);
        }
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DATE));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取去年的起始时间
     *
     * @return Timestamp
     */
    public static Timestamp getPreviousYearZeroTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.YEAR, -1);
        calendar.set(Calendar.MONTH, Calendar.JANUARY);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取去年的结束时间
     *
     * @return Timestamp
     */
    public static Timestamp getPreviousYearLastTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.add(Calendar.YEAR, -1);
        calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DATE));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 根据事件段获取x坐标
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param num       段
     * @return list
     */
    public static List<Timestamp> getTimeAxisX(Timestamp startTime, Timestamp endTime, int num) {
        List<Timestamp> axisX = new ArrayList<>();
        axisX.add(startTime);
        long start = startTime.getTime();
        BigDecimal betweenMin = new BigDecimal(minBetween(startTime, endTime)).divide(new BigDecimal(num - 1), 3, BigDecimal.ROUND_HALF_UP);
        long temp = new BigDecimal(1000 * 60).multiply(betweenMin).longValue();
        for (int i = 0; i < (num - NUM_2); i++) {
            start += temp;
            axisX.add(new Timestamp(start));
        }
        axisX.add(endTime);
        return axisX;
    }

    /**
     * 获取时间段的天数间隔
     *
     * @param start 开始时间
     * @param end   结束时间
     * @return 天数
     */
    public static int diffDays(LocalDateTime start, LocalDateTime end) {
        return (int) Math.floor((double) Duration.between(start, end).toMillis() / (24 * 60 * 60 * 1000));
    }

    private static long minBetween(Timestamp startTime, Timestamp endTime) {
        long start = startTime.getTime();
        long end = endTime.getTime();
        return (end - start) / (1000 * 60);
    }

    public static String timestampToDateStr(long timestamp) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long stamp = Long.valueOf(timestamp);
        String res = sdf.format(new Date(stamp));
        return res;
    }
}

